package org.m2acsi.control;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.ManagedBean;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import org.m2acsi.boundary.ConsultationEJB;
import org.m2acsi.entities.Consultation;
import org.m2acsi.entities.Document;
import org.m2acsi.entities.Download;
import org.m2acsi.entities.Message;
import org.m2acsi.entities.Opinion;
import org.m2acsi.entities.RoleType;
import org.m2acsi.entities.Task;
import org.m2acsi.entities.User;
import org.m2acsi.utils.Security;

@Named
@RequestScoped
@ManagedBean
public class TaskBean extends BaseBean implements Serializable {

    private Task task = new Task();
    private List<Task> tasks;
    @Inject
    private ConsultationEJB consultationEJB;

    public TaskBean() {
        super();
        tasks = new ArrayList<>();
    }

    public Task getTask() {
        if (task.getDeadline() == null) {
            securityCheck();
        }
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }

    public List<Task> getTasks() {
        loadTasks();
        return tasks;
    }

    public List<Task> getTasksWithNotifications() {
        List<Task> result = new ArrayList<>();
        for (Iterator<Task> it = getOngoing().iterator(); it.hasNext();) {
            Task t = it.next();
            if (t.getNotifications() > 0) {
                result.add(t);
            }
        }
        for (Iterator<Task> it = getClosed().iterator(); it.hasNext();) {
            Task t = it.next();
            if (t.getNotifications() > 0) {
                result.add(t);
            }
        }
        return result;
    }

    public void setTasks(List<Task> tasks) {
        this.tasks = tasks;
    }

    public List<Task> getOpenTasks() {
        List<Task> openTask = new LinkedList<>();
        Date currentDate = new Date();
        for (Task t : taskEjb.findAll()) {
            if (t.getDeadline().compareTo(currentDate) == 1 && !t.isClosedByAdmin()) {
                openTask.add(t);
            }
        }
        Collections.sort(openTask, new Comparator<Task>() {

            @Override
            public int compare(Task t, Task t1) {
                return t.getDeadline().compareTo(t1.getDeadline());
            }
        });
        return openTask;
    }

    public List<Task> getCloseTasks() {
        List<Task> closeTask = new LinkedList<>();
        Date currentDate = new Date();
        for (Task t
                : taskEjb.findAll()) {
            if (t.getDeadline().compareTo(currentDate) == -1 || t.isClosedByAdmin()) {
                closeTask.add(t);
            }
        }

        Collections.sort(closeTask,
                new Comparator<Task>() {

                    @Override
                    public int compare(Task t, Task t1
                    ) {
                        return t1.getDeadline().compareTo(t.getDeadline());
                    }
                }
        );
        return closeTask;
    }

    public void loadTasks() {
        //TODO restrict to user's rights
        tasks = taskEjb.findAll();
    }

    public List<Task> getOngoing() {
        User user = getAuthenticatedUser();
        List<Task> ongoing = new LinkedList<>();
        for (Task t : getAuthenticatedUser().getContributions()) {
            if (t.getDeadline().compareTo(new Date()) == 1 && !t.isClosedByAdmin()) {
                computeTaskNotifications(t, user);
                ongoing.add(t);
            }
        }
        if (getAuthenticatedUser().getRoleName().equals(RoleType.ADMIN)) {
            for (Task t : getAuthenticatedUser().getAuthor()) {
                if (t.getDeadline().compareTo(new Date()) == 1 && !t.isClosedByAdmin()) {
                    computeTaskNotifications(t, user);
                    ongoing.add(t);
                }
            }
        }

        Collections.sort(ongoing, new Comparator<Task>() {

            @Override
            public int compare(Task t, Task t1) {
                return t.getDeadline().compareTo(t1.getDeadline());
            }
        });
        return ongoing;
    }

    public List<Task> getClosed() {
        User user = getAuthenticatedUser();
        List<Task> closed = new LinkedList<>();
        for (Task t : getAuthenticatedUser().getContributions()) {
            if (t.getDeadline().compareTo(new Date()) <= 0 || t.isClosedByAdmin()) {
                computeTaskNotifications(t, user);
                closed.add(t);
            }
        }
        if (getAuthenticatedUser().getRoleName().equals(RoleType.ADMIN)) {
            for (Task t : getAuthenticatedUser().getAuthor()) {
                if (t.getDeadline().compareTo(new Date()) <= 0 || t.isClosedByAdmin()) {
                    computeTaskNotifications(t, user);
                    closed.add(t);
                }
            }
        }

        Collections.sort(closed, new Comparator<Task>() {

            @Override
            public int compare(Task t, Task t1) {
                return t.getDeadline().compareTo(t1.getDeadline());
            }
        });
        return closed;
    }

    public void closeTask() {
        task = Security.taskSecurityCheck(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"), getAuthenticatedUser(), taskEjb, this);
        task.setClosedByAdmin(true);
        taskEjb.update(task);
        redirect("/faces/user/index.xhtml");
    }

    public void securityCheck() {
        task = Security.taskSecurityCheck(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"), getAuthenticatedUser(), taskEjb, this);
        loadTasks();
    }

    public void consult() {
        String idTaskString = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
        Task tmpTask = Security.taskSecurityCheck(idTaskString, getAuthenticatedUser(), taskEjb, this);
        Consultation c = new Consultation();
        c.setTask(tmpTask);
        c.setUser(getAuthenticatedUser());
        consultationEJB.save(c);
    }

    private void computeTaskNotifications(Task t, User user) {
        int notifications = 0;
        Date lastVisit = consultationEJB.lastConsultation(t, user);
        for (Iterator<Document> it1 = t.getDocuments().iterator(); it1.hasNext();) {
            Document d = it1.next();
            notifications++;
            for (Iterator<Download> it2 = d.getDownloads().iterator(); it2.hasNext();) {
                Download dl = it2.next();
                if (dl.getUser().getId() == user.getId()) {
                    notifications--;
                    break;
                }
            }
        }
        for (Iterator<Message> it1 = t.getMessages().iterator(); it1.hasNext();) {
            Message m = it1.next();
            if (lastVisit == null || m.getCreationDate().compareTo(lastVisit) > 0) {
                notifications++;
            }
        }
        for (Iterator<Opinion> it1 = t.getOpinions().iterator(); it1.hasNext();) {
            Opinion o = it1.next();
            if (lastVisit == null || o.getCreationDate().compareTo(lastVisit) > 0) {
                notifications++;
            }
        }
        t.setNotifications(notifications);
    }
}
